package com.hulk.dryad.admin.service.impl;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hulk.dryad.common.constant.CacheConstants;
import com.hulk.dryad.common.constant.CommonConstants;
import com.hulk.dryad.common.constant.SecurityConstants;
import com.hulk.dryad.common.constant.enums.RootFlag;
import com.hulk.dryad.manage.provider.service.SysDeptRelationService;
import com.hulk.dryad.manage.provider.service.SysDeptService;
import com.hulk.dryad.persistence.injector.datascope.DataScope;
import com.hulk.dryad.persistence.entity.*;
import com.hulk.dryad.persistence.mapper.SysUserMapper;
import com.hulk.dryad.admin.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author kim
 * @date 2019/10/31
 */
@DS("#" + CommonConstants.TENANT_ID)
@Slf4j
@Service
@RequiredArgsConstructor
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUserModel> implements SysUserService {

	private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();

	private final SysMenuService sysMenuService;

	private final SysRoleService sysRoleService;

	private final SysDeptService sysDeptService;

	private final SysUserRoleService sysUserRoleService;

	private final SysDeptRelationService sysDeptRelationService;

	private final SysUserPostService  sysUserPostService;

	private final SysPostService  sysPostService;


	/**
	 * 保存用户信息
	 * @param extModel DTO 对象
	 * @return boolean
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean saveUser(UserExtModel extModel) {
		SysUserModel sysUser = new SysUserModel();
		BeanUtils.copyProperties(extModel, sysUser);
		sysUser.setDelFlag(CommonConstants.STATUS_NORMAL);
		sysUser.setPassword(ENCODER.encode(extModel.getPassword()));
		sysUser.setCreatedTime(LocalDateTime.now());
		super.save(sysUser);
		List<SysUserPost> userPosts =extModel.getPost().stream().map(
				v->{
					SysUserPost up= new SysUserPost();
					up.setPostId(v);
					up.setUserId(sysUser.getUserId());
					return up;
				}
		).collect(Collectors.toList());
		sysUserPostService.saveReplaceBatch(userPosts);
		List<SysUserRoleModel> userRoleList = extModel.getRole().stream().map(roleId -> {
			SysUserRoleModel userRole = new SysUserRoleModel();
			userRole.setUserId(sysUser.getUserId());
			userRole.setRoleId(roleId);
			return userRole;
		}).collect(Collectors.toList());
		return sysUserRoleService.saveBatch(userRoleList);
	}

	/**
	 * 通过查用户的全部信息
	 * @param sysUser 用户
	 * @return UserInfoModel
	 */
	@Override
	@Cacheable(value = CacheConstants.USER_DETAILS + "#10s",key = "#sysUser.username",unless = "#result == null ")
	public UserInfoModel findUserInfo(SysUserModel sysUser) {
		UserInfoModel userInfoModel = new UserInfoModel();
		userInfoModel.setSysUserModel(sysUser);
		List<Integer> roleIds = new ArrayList<>();
		List<String> roleCodes = new ArrayList<>();
		Set<String> permissions = new HashSet<>();
		Set<Long> postIds = new HashSet<>();
		if (!RootFlag.ROOT.getValue().equalsIgnoreCase(sysUser.getRootFlag())) {
			  // 设置角色列表 （ID）
			  List<SysRoleModel> userRoles = sysRoleService.findRolesByUserId(sysUser.getUserId());
			  // 设置角色列表 （ID）
			  roleIds.addAll(userRoles.stream().map(SysRoleModel::getRoleId).collect(Collectors.toList())) ;
			  // 设置角色名称列表
			  roleCodes.addAll(userRoles.stream().map(SysRoleModel::getRoleCode).collect(Collectors.toList()));
			  // 设置权限列表（menu.permission）
			  roleIds.forEach(
				  roleId -> {
					List<String> permissionList =
						sysMenuService.findMenuByRoleId(roleId).stream()
							.filter(menu -> StringUtils.isNotEmpty(menu.getPermission()))
							.map(SysMenuModel::getPermission)
							.collect(Collectors.toList());
					permissions.addAll(permissionList);
				  });

			postIds.addAll(sysUserPostService.getPostIdsByUserId(sysUser.getUserId()));
			}else {
				List<SysRoleModel> roles  = sysRoleService.findAllRole();
				// 设置角色列表 （ID）
				roleIds.addAll(roles.stream().map(SysRoleModel::getRoleId).collect(Collectors.toList()));
				// 设置角色名称列表
				roleCodes.addAll(roles.stream().map(SysRoleModel::getRoleCode).collect(Collectors.toList()));
			    List<String> permissionList = sysMenuService.findAllMenu().stream()
							.filter(menu -> StringUtils.isNotEmpty(menu.getPermission()))
							.map(SysMenuModel::getPermission)
							.collect(Collectors.toList());
			    permissions.addAll(permissionList);
			   	postIds.addAll(sysPostService.getAllPostIds());
		}
		////ROLE_ADMIN 用户添加ACTIVITI权限
		if(roleCodes.contains(SecurityConstants.ROLE_ADMIN)){
			roleCodes.clear();
			roleCodes.add(SecurityConstants.ROLE_ACTIVITI_ADMIN);
		}else {
			roleCodes.clear();
			roleCodes.add(SecurityConstants.ROLE_ACTIVITI_USER);
		}
		userInfoModel.setRoles(ArrayUtil.toArray(roleIds, Integer.class));
		userInfoModel.setRoleCodes(ArrayUtil.toArray(roleCodes, String.class));
		userInfoModel.setPermissions(ArrayUtil.toArray(permissions, String.class));
		userInfoModel.setPosts(ArrayUtil.toArray(postIds, Long.class));
		return userInfoModel;
	}

	/**
	 * 分页查询用户信息（含有角色信息）
	 * @param page 分页对象
	 * @param sysUserModel 参数列表
	 * @return IPage
	 */
	@Override
	public Page<UserViewModel>  getUsersWithRolePage(Page page, SysUserModel sysUserModel) {
		return baseMapper.getUserVosPage(page, sysUserModel, new DataScope());
	}

	/**
	 * 通过ID查询用户信息
	 * @param id 用户ID
	 * @return 用户信息
	 */
	@Override
	public UserViewModel selectUserVoById(Integer id) {
		return baseMapper.getUserVoById(id);
	}

	/**
	 * 删除用户
	 * @param sysUser 用户
	 * @return Boolean
	 */
	@Override
	@CacheEvict(value = CacheConstants.USER_DETAILS, key = "#sysUser.username")
	public Boolean removeUserById(SysUserModel sysUser) {
		sysUserRoleService.removeByUserId(sysUser.getUserId());
		sysUserPostService.removeByUserId(sysUser.getUserId());
		this.removeById(sysUser.getUserId());
		return Boolean.TRUE;
	}
	/**
	 * 更新个人用户信息
	 * @param extModel 用户
	 * @return Boolean
	 */
	@Deprecated
	@Override
	@CacheEvict(value = CacheConstants.USER_DETAILS, key = "#extModel.username")
	public Boolean updateUserInfo(UserExtModel extModel) {
		UserViewModel userModel = baseMapper.getUserVoByUsername(extModel.getUsername());
		if (!ENCODER.matches(extModel.getPassword(), userModel.getPassword())) {
			log.info("原密码错误，修改个人信息失败:{}", extModel.getUsername());
			return Boolean.FALSE;
		}

		SysUserModel sysUser = new SysUserModel();
		if (StrUtil.isNotBlank(extModel.getNewpassword1())) {
			sysUser.setPassword(ENCODER.encode(extModel.getNewpassword1()));
		}
		sysUser.setPhone(extModel.getPhone());
		sysUser.setUserId(userModel.getUserId());
		sysUser.setAvatar(extModel.getAvatar());
		return this.updateById(sysUser);
	}
	/**
	 * 更新用户信息
	 * @param extModel 用户
	 * @return Boolean
	 */
	@Override
	@CacheEvict(value = CacheConstants.USER_DETAILS, key = "#extModel.username")
	public Boolean updateUser(UserExtModel extModel) {
		SysUserModel sysUser = new SysUserModel();
		BeanUtils.copyProperties(extModel, sysUser);
		sysUser.setUpdatedTime(LocalDateTime.now());

		if (StrUtil.isNotBlank(extModel.getPassword())) {
			sysUser.setPassword(ENCODER.encode(extModel.getPassword()));
		}
		this.updateById(sysUser);
		sysUserPostService
				.remove(Wrappers.<SysUserPost>update().lambda().eq(SysUserPost::getUserId, extModel.getUserId()));
		extModel.getPost().forEach(postId -> {
			SysUserPost userPost = new SysUserPost();
			userPost.setUserId(sysUser.getUserId());
			userPost.setPostId(postId);
			userPost.insert();
		});

		sysUserRoleService
				.remove(Wrappers.<SysUserRoleModel>update().lambda().eq(SysUserRoleModel::getUserId, extModel.getUserId()));
		extModel.getRole().forEach(roleId -> {
			SysUserRoleModel userRole = new SysUserRoleModel();
			userRole.setUserId(sysUser.getUserId());
			userRole.setRoleId(roleId);
			userRole.insert();
		});
		return Boolean.TRUE;
	}

	/**
	 * 查询上级部门的用户信息
	 * @param username 用户名
	 * @return List
	 */
	@Override
	public List<SysUserModel> listAncestorUsers(String username) {
		SysUserModel sysUser = this.getOne(Wrappers.<SysUserModel>query().lambda().eq(SysUserModel::getUsername, username));

		SysDeptModel sysDeptModel = sysDeptService.getById(sysUser.getDeptId());
		if (sysDeptModel == null) {
			return null;
		}

		Integer parentId = sysDeptModel.getParentId();
		return this.list(Wrappers.<SysUserModel>query().lambda().eq(SysUserModel::getDeptId, parentId));
	}

	/**
	 * 获取当前用户的子部门信息
	 * @return 子部门列表
	 */
	private List<Integer> getChildDepts(Integer deptId) {
		/** 获取当前部门的子部门*/
		return sysDeptRelationService
				.list(Wrappers.<SysDeptRelationModel>query().lambda().eq(SysDeptRelationModel::getAncestor, deptId)).stream()
				.map(SysDeptRelationModel::getDescendant).collect(Collectors.toList());
	}

	/**
	 * 通过用户名查询用户信息
	 * @param username 用户名
	 * @return SysUserModel
	 */
	@Override
	public SysUserModel getUserByName(String username) {
		LambdaQueryWrapper<SysUserModel> qw = Wrappers.<SysUserModel>lambdaQuery()
				.eq(SysUserModel::getUsername, username);
		return this.getOne(qw);
	}

}
